﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Linq;
using System.Reflection;
using System.IO;

namespace SPListsCaller.WS
{
    [Serializable]
    public class GetListItems_CallParameters : INotifyPropertyChanged
    {
        //---------------------------------------------------------------------
        #region Variables & accesseurs
        //---------------------------------------------------------------------

        private string _listName;
        /// <summary>
        /// ListName
        /// </summary>
        [XmlAttribute]
        public string ListName
        {
            get { return _listName; }
            set
            {
                _listName = value;
                OnPropertyChanged("ListName");
            }
        }

        private string _viewName;
        /// <summary>
        /// ViewName
        /// </summary>
        [XmlAttribute]
        public string ViewName
        {
            get { return _viewName; }
            set
            {
                _viewName = value;
                OnPropertyChanged("ViewName");
            }
        }

        private int _rowLimit;
        /// <summary>
        /// RowLimit
        /// </summary>
        [XmlAttribute]
        public int RowLimit
        {
            get { return _rowLimit; }
            set
            {
                _rowLimit = value;
                OnPropertyChanged("RowLimit");
            }
        }

        private string _query;
        /// <summary>
        /// Query
        /// </summary>
        [XmlAttribute]
        public string Query
        {
            get { return _query; }
            set
            {
                _query = value;
                OnPropertyChanged("Query");
            }
        }

        private string _viewFields;
        /// <summary>
        /// ViewFields
        /// </summary>
        [XmlAttribute]
        public string ViewFields
        {
            get { return _viewFields; }
            set
            {
                _viewFields = value;
                OnPropertyChanged("ViewFields");
            }
        }

        private string _queryOptions;
        /// <summary>
        /// QueryOptions
        /// </summary>
        [XmlAttribute]
        public string QueryOptions
        {
            get { return _queryOptions; }
            set
            {
                _queryOptions = value;
                OnPropertyChanged("QueryOptions");
            }
        }

        //---------------------------------------------------------------------
        #endregion Variables & accesseurs
        //---------------------------------------------------------------------

        //---------------------------------------------------------------------
        #region Méthodes
        //---------------------------------------------------------------------

        public void Export(string fileName)
        {
            XDocument exportDoc = new XDocument();
            XElement rootElement = new XElement("GetListItems_CallParameters");
            exportDoc.Add(rootElement);

            IEnumerable<XElement> xProperties = typeof(GetListItems_CallParameters).GetProperties()
                .Cast<PropertyInfo>()
                .Select(pi =>
                    {
                        XElement result = new XElement(pi.Name);
                        object oBuffer = pi.GetValue(this, null);
                        string sBuffer = oBuffer == null ? string.Empty : oBuffer.ToString();

                        try
                        {
                            XElement xBuffer = XElement.Parse(sBuffer);
                            result.Add(xBuffer);
                        }
                        catch
                        {
                            try
                            {
                                XElement xBuffer = XElement.Parse("<Buffer>" + sBuffer + "</Buffer>");
                                if (xBuffer.Elements().Count() > 0)
                                {
                                    result.Add(xBuffer.Elements());
                                }
                                else
                                {
                                    result.SetValue(sBuffer);
                                }
                            }
                            catch
                            {
                                result.SetValue(sBuffer);
                            }
                        }

                        return result;
                    });

            rootElement.Add(xProperties.ToArray());

            // Enregistrement
            exportDoc.Save(fileName);
        }

        public static GetListItems_CallParameters LoadFrom(string fileName)
        {
            GetListItems_CallParameters result = new GetListItems_CallParameters();
            //------------------------------------------------------------------------------------------

            XDocument importDoc = XDocument.Load(fileName);


            PropertyInfo[] resultProperties = typeof(GetListItems_CallParameters).GetProperties();

            foreach (PropertyInfo pi in resultProperties)
            {
                string propertyName = pi.Name;
                XElement pixElement = importDoc.Descendants(propertyName).FirstOrDefault();

                if (pixElement != null)
                {
                    if (pixElement.Nodes().Count() > 0)
                    {
                        string sBuffer = string.Join(string.Empty, pixElement.Nodes().Select(node => node.ToString(SaveOptions.DisableFormatting)).ToArray());

                        pi.SetValue(result, Convert.ChangeType(sBuffer, pi.PropertyType), null);
                        result.OnPropertyChanged(pi.Name);
                    }
                }
            }

            //------------------------------------------------------------------------------------------
            return result;
        }

        public GetListItems_CallParameters Clone()
        {
            GetListItems_CallParameters result = null;
            //------------------------------------------------------------------------------------------

            XmlSerializer xSer = new XmlSerializer(typeof(GetListItems_CallParameters));
            using (MemoryStream ms = new MemoryStream())
            {
                xSer.Serialize(ms, this);
                ms.Seek(0, SeekOrigin.Begin);
                result = (GetListItems_CallParameters)xSer.Deserialize(ms);
            }

            //------------------------------------------------------------------------------------------
            return result;
        }

        //---------------------------------------------------------------------
        #endregion Méthodes
        //---------------------------------------------------------------------

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public GetListItems_CallParameters GetNextPagedCallParameter(XmlNode queryResult)
        {
            GetListItems_CallParameters result = null;
            //---------------------------------------------------------------------------------------

            XmlNamespaceManager xNsMan = new XmlNamespaceManager(new NameTable());
            xNsMan.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");

            // Récupération du noeud correspondant à la pagination
            XmlNode positionNext = queryResult.SelectSingleNode("//@ListItemCollectionPositionNext");
            if (positionNext != null)
            {
                // Si le noeud existe, on initialise la prochaine requête
                result = this.Clone();


                // On doit remplacer l'éventuel noeud de pagination (QueryOption)
                // --> S'il n'existe pas, on le crée.
                XElement xeBuffer = XElement.Parse("<Buffer>" + this.QueryOptions + "</Buffer>");
                XElement xePaging = xeBuffer.Element("Paging");
                if (xePaging == null)
                {
                    xePaging = new XElement("Paging");
                    xeBuffer.Add(xePaging);
                }
                xePaging.SetAttributeValue("ListItemCollectionPositionNext", positionNext.Value);

                result.QueryOptions = string.Join(string.Empty, xeBuffer.Nodes().Select(node => node.ToString(SaveOptions.DisableFormatting)).ToArray());
            }

            //---------------------------------------------------------------------------------------
            return result;
        }
    }
}
